package com.marui.ch3;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * ABA问题的演示和解决方案
 */
public class ABADemo {

    static AtomicReference<String> reference = new AtomicReference<>("ma");
    static AtomicStampedReference<String> stampedReference =
            new AtomicStampedReference("ma", 0);


    public static void main(String[] args) throws Exception {

        AbaSolution();

        //AbaPro();


    }

    /**
     * ABA问题的解决方案
     */
    private static void AbaSolution() throws InterruptedException {
        int stamp = stampedReference.getStamp();
        String reference = stampedReference.getReference();
        System.out.println("main\t" + stamp + "\t" + reference);
        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            int newStamp = stamp + 1;
            Boolean flag = stampedReference.compareAndSet(reference, "marui", stampedReference.getStamp(), newStamp);
            System.out.println("1更新成功" + flag + "\t版本号为:" + stampedReference.getStamp()
                    + "\t值为:" + stampedReference.getReference());

            Boolean flag2 = stampedReference.compareAndSet("marui", "ma", newStamp, newStamp + 1);
            System.out.println("2更新成功" + flag2 + "\t版本号为:" + stampedReference.getStamp()
                    + "\t值为:" + stampedReference.getReference());
        }).start();


        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Boolean flag = stampedReference.compareAndSet("ma", "madaha",
                    stamp, stamp + 1);
            System.out.println("3更新成功" + flag + "\t版本号为:" + stampedReference.getStamp() + "\t值为:" +
                    stampedReference.getReference());
        }).start();
    }

    /**
     * ABA问题演示
     */
    private static void AbaPro() {
        new Thread(() -> {
            reference.compareAndSet("ma", "marui");
            reference.compareAndSet("marui", "ma");
        }).start();


        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reference.compareAndSet("ma", "madaha");
            System.out.println(reference.get());
        }).start();
    }


}
